/**
 * 
 */
package com.ej.generics;

import java.util.HashMap;
import java.util.Map;

/**
 * Consider typesafe heterogeneous containers. The limitation to have a fixed
 * number of type parameters per container [Like HashMap<T>, List<T>] can be
 * overcome by using heterogeneous containers
 * 
 * @author Sunaina.Sharma
 * 
 */
public class TypeSafeHeterContainers {

	/*
	 * When a class literal is passed among methods to communicate both
	 * compile-time and runtime type information, it is called a type token
	 */

	// Typesafe heterogeneous container pattern - implementation
	class Favorites {
		private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();

		/**
		 * @param <T>
		 * @param type
		 * @param instance
		 */
		public <T> void putFavorite(Class<T> type, T instance) {
			if (type == null)
				throw new NullPointerException("Type is null");
			favorites.put(type, instance);
		}

		/**
		 * @param <T>
		 * @param type
		 * @return
		 */
		public <T> T getFavorite(Class<T> type) {
			// This is to cast the object reference to the type
			// represented by the Class object
			return type.cast(favorites.get(type));
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		TypeSafeHeterContainers tshf = new TypeSafeHeterContainers();
		Favorites f = tshf.new Favorites();
		f.putFavorite(String.class, "Java");
		f.putFavorite(Integer.class, 0xcafebabe);
		f.putFavorite(Class.class, Favorites.class);

		String favoriteString = f.getFavorite(String.class);
		int favoriteInteger = f.getFavorite(Integer.class);
		Class<?> favoriteClass = f.getFavorite(Class.class);
		System.out.printf("%s %x %s%n", favoriteString, favoriteInteger,
				favoriteClass.getName());
	}
}
